package com.yc.baseProgram;

import java.util.ArrayList;
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;

public class TestLambda {
	
	/**
	 * 功能：
	 * 传入一个参数，用函数处理一下，返回一个int。
	 * 具体怎么处理，也由调用者决定
	 * @param a			传入的待处理的参数
	 * @param function	调用者传入的函数，用来处理参数a的
	 * @return
	 */
	public int testFunction(int a, Function<Integer, Integer> function) {
		return function.apply(a);//apply 接收一个参数，传入function函数，得到结果
	}
	
	/**
	 * 函数组合
	 * @param a
	 * @param function1
	 * @param function2
	 * @return
	 * 先计算function2，然后返回这个中间值（是个函数），然后再用function1计算
	 */
	public int testCompose(int a, Function<Integer, Integer> function1, Function<Integer, Integer> function2) {
		
		return function1.compose(function2).apply(a);
	}
	
	public int compute(int a, Function<Integer, Integer> function1, Function<Integer, Integer> function2) {
	    return function1.compose(function2).apply(a);
	}
	
	//编译阶段就知道有错误，执行了一遍？。不，是编译。。
	public int compute2(int a, Function<Integer, Integer> function1, Function<Integer, Integer> function2) {
	    return function1.compose(function2).apply(a);
	}
	
	/**
	 * 和Compose相反。这是先算function1，然后算function2
	 * @param a
	 * @param function1
	 * @param function2
	 * @return
	 */
	public int testAndThen(int a, Function<Integer, Integer> function1, Function<Integer, Integer> function2) {
		return function1.andThen(function2).apply(a);
	}
	
	/**
	 * 两个参数的函数
	 * @param a
	 * @param b
	 * @param function
	 * @return
	 */
	public int testFunctionalInterface(int a, int b, BiFunction<Integer, Integer, Integer> function) {
		
		return function.apply(a, b);
	}
	
	/**
	 * 先执行function（返回一个值） 然后执行function2
	 * @param a
	 * @param b
	 * @param function
	 * @param function2
	 * @return
	 */
	public int testBiFunctionAndThen(int a, int b, BiFunction<Integer, Integer, Integer> function, Function<Integer, Integer> function2) {
		return function.andThen(function2).apply(a, b);
	}
	
	
	Integer a = 0;
	/**
	 * 消费者
	 * Local variable xxx defined in an enclosing scope must be final or effectively final
	 */
	public void testConsumer() {
		Consumer<String> printString = s -> System.out.println(s);
        printString.accept("helloWorld!");
        printString.accept("helloWorld2!");
        //控制台输出 helloWorld!
//        int a = 0;
        Consumer<Integer> sumA = s -> a+=s;
        for (int i = 1; i < 101; i++) {
        	sumA.accept(i);
		}
        System.out.println("a=" + a);
	}
	
	public void testConsumer2() {
		myConsumer printString = new myConsumer();
        printString.accept("helloWorld3!");
        printString.accept("helloWorld4!");
        
	}
	
	/**
	 * 提供者：只出不进
	 * 适用场景
	 */
	public void testSupplier() {
		Supplier<String> getInstance = () -> "HelloWorld!--testSupplier";
        System.out.println(getInstance.get());
        // 控偶值台输出 HelloWorld
	}
	
	/**
	 * 谓语：特殊的Function，但返回值固定为boolean类型，用于判断真/假
	 */
	public void testPredicate() {
		Predicate<Integer> predOdd = integer -> integer % 2 == 1;
        System.out.println(predOdd.test(5));
        //控制台输出 true
	}
	
	//消费者的应用之一：集合的foreach
	public void testIterable() {
		Consumer<String> printString = s -> System.out.println(s);
		List<String> a = new ArrayList<String>();
		a.add("aa");
		a.add("b");
//		a.forEach(printString);//两种写法都可以
		a.forEach(s -> System.out.println(s));
		
	}
	
	/**
	 * 任何接口都可以用函数表示：函数式接口@FunctionInterface
	 * 比较Consumer，Runable ： 函数内容是否和抽象方法有关
	 * Runable可以像Consumer一样写成函数，此时的函数值得就是run（或等效）方法
	 * Consumer是否可以像Runable一样 实现，然后new，那么我们
	 * 两者概念是否统一
	 */
	public void testRunable() {
		//写法1
		new Thread(() -> {
			System.out.println("--");
		}).start();
		
		//写法2
		Runnable r = () -> {System.out.println("--");};
		new Thread(r).start();
		
		//写法3
		new Thread(new myRunnable()).start();
	}
	
	class myRunnable implements Runnable {

		@Override
		public void run() {
			System.out.println("---");
			
		}
		
	}
	
	class myConsumer implements Consumer {

		@Override
		public void accept(Object t) {
			
			System.out.println(t.toString());
		}
		
	}
	
	class myFunction implements Function<Integer, Integer> {

		@Override
		public Integer apply(Integer t) {
			return t*t;
		}

	}
	
	public void testFunction23() {
		TestLambda tl = new TestLambda();
		Function<Integer, Integer> function4 = new myFunction();
		tl.testFunction(2, function4);
	}
	

	public static void main(String[] args) {
		TestLambda tl = new TestLambda();
		
		// testFunction
		int res1 = tl.testFunction(2, a -> a*a);
		System.out.println("res1 = " + res1);
		Function<Integer, Integer> function2 = (a) -> {int c=a*a;System.out.println("res2 = " + c);return c;};
		Function<Integer, Integer> function3 = (a) -> {return a*a;};
		Function<Integer, Integer> function4 = (Integer a) -> {return a*a;};
		Function<Integer, Integer> function5 = (a) -> {System.out.println("res2 = " + a); return a;};
		tl.testFunction23();
		
		//testCompose
		int res2 = tl.testCompose(2, a -> a*a, b -> b + 2);
		System.out.println("res2 = " + res2);//(2+2)*(2+2)=16
		
		int res3 = tl.compute(2, value -> value * 3, value -> value * value);
		System.out.println("res3 = " + res3);//2*2*3=12
		
		//testAndThen
		int res4 = tl.testAndThen(2, value -> value * 3, value -> value * value);
		System.out.println("res4 = " + res4);//(2*3)*(2*3)=36
		
		//testFunctionalInterface
		int res5 = tl.testFunctionalInterface(2, 3, (value1, value2) -> value1 * value2);
		System.out.println("res5 = " + res5);//2*3=6
		
		//testBiFunctionAndThen
		int res6 = tl.testBiFunctionAndThen(2, 3, (value1, value2) -> value1 * value2, a -> a + 1);
		System.out.println("res6 = " + res6);//2*3 + 1 =7
		
		System.out.println("----------------------------------");
		tl.testConsumer();
		tl.testConsumer2();
		tl.testIterable();
		tl.testSupplier();
		tl.testPredicate();
	}

}
